home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-04-28 | 10.1 KB | 395 lines | [TEXT/MPS ] |
- /*
- File: DialogUtils.cp
-
- Contains: Auto-sized error alert mechanism,
- ModalFilterProcs which correctly handle events,
- and Standard “Close Document” dialogs.
-
- Written by: Dave Falkenburg
-
- Copyright: © 1993-94 by Dave Falkenburg, all rights reserved.
-
- Change History (most recent first):
-
- <5> 11/16/94 DRF Added explicit #include <SegLoad.h> for latest universal
- headers. Also added cast to keep MPW CFront happier.
- <4> 11/16/94 DRF Add StdFilterProc for THINK C.
- <3> 9/27/94 DRF AppLib.h is now Sprocket.h
- <2> 9/9/94 DRF Reordered headers and removed redundant #includes.
- */
-
- #include "Sprocket.h"
-
- #include <Fonts.h>
- #include <Resources.h>
- #include <TextUtils.h>
- #include <Threads.h> // For YieldToAnyThread()
- #include <StandardFile.h> // For ModalFilterYDProcPtr
- #include <SegLoad.h> // For ExitToShell()
-
- #if GENERATINGCFM
- QDGlobals qd;
- #endif
-
- // Some types which should probably be defined in <Dialogs.h>
- // NOTE: These must be aligned on 2-byte boundaries
- #if defined(powerc) || defined (__powerc)
- #pragma options align=mac68k
- #endif
-
- struct DialogItem
- {
- long usedByDialogManager;
- Rect boundsRect;
- char type;
- char length;
- };
-
- struct DialogItemList // a.k.a. a 'DITL'
- {
- short count;
- DialogItem firstItem[1];
- };
-
- // Restore default alignment
- #if defined(powerc) || defined(__powerc)
- #pragma options align=reset
- #endif
-
- typedef DialogItem *DialogItemPtr;
- typedef DialogItemList **DialogItemListHandle;
- typedef DialogTemplate **DialogTemplateHandle;
-
- #ifndef powerc
- #ifdef __SC__
-
- #ifdef __CFM68K__
- #pragma lib_export on
- #endif
-
- extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
- THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
-
- #ifdef __CFM68K__
- #pragma lib_export off
- #endif
-
- pascal Boolean
- StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
- {
- ModalFilterUPP filterUPP;
-
- // Dialogs.h
-
- (void) GetStdFilterProc(&filterUPP);
-
- return CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
- }
-
- #endif
- #endif
-
- // private function Prototypes
-
- static pascal Boolean StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
- static pascal Boolean StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
- static pascal Boolean StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
- static Boolean FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
-
-
-
- ///////////////////////////////////////////////////////////
- //
- // StandardAlert
- //
- // An alternative to Alert() which uses the extended
- // Dialog Manager capabilities.
- //
- // I’m not sure we really need this call, but it seems
- // to do the trick just fine.
-
- short
- StandardAlert( short dlogID,
- short defaultItem, /* = ok */
- short cancelItem, /* = 0 */
- ModalFilterUPP customFilterProc /* = nil */)
- {
- DialogPtr theDialog;
- short itemHit = 0;
- ModalFilterUPP filterToUse;
-
- HiliteWindowsForModalDialog(false);
-
- theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
- if (defaultItem)
- SetDialogDefaultItem(theDialog,defaultItem);
- if (cancelItem)
- SetDialogCancelItem(theDialog,cancelItem);
-
- if (customFilterProc)
- filterToUse = customFilterProc;
- else
- filterToUse = StandardDialogFilter;
-
- do
- ModalDialog(filterToUse,&itemHit);
- while (itemHit == 0);
-
- DisposeDialog(theDialog);
-
- HiliteWindowsForModalDialog(true);
-
- return itemHit;
- }
-
-
- ///////////////////////////////////////////////////////////
- //
- // ErrorAlert
- //
- // A nice error reporting routine which presents an
- // auto-sized alert box containing the supplied text.
- //
- // NOTE: This routine ASSUMES the following 'DITL'
- // structure:
- //
- // item #1 : an “OK” button
- // item #2 : a static text item, somewhere above #1
- //
- // NOTE: We probably need to worry more about low
- // memory conditions-- this can probably
- // be handled by a custom GrowZoneProc and
- // reserve memory area large enough to hold
- // all the space we’d need.
- //
-
- void
- ErrorAlert(short stringList,short whichString)
- {
- Str255 errorString;
- GrafPtr oldPort,windowMgrPort;
- short oldFont;
- DialogTemplateHandle errorDialogTemplate;
- DialogItemListHandle errorDialogItems;
- TEHandle aTEHandle;
- Rect textRect;
- short textHeight;
- short additionalSpaceNeeded;
- DialogItemPtr okButtonItem,errorTextItem;
- const StringPtr nullStr = (StringPtr) "\p";
-
- GetIndString(errorString,stringList,whichString);
-
- errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
- HLock((Handle) errorDialogTemplate);
-
- errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
- HLock((Handle) errorDialogItems);
-
- // Find the dialog items
-
- okButtonItem = (**errorDialogItems).firstItem;
- errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
-
- GetPort(&oldPort);
- GetWMgrPort(&windowMgrPort);
- SetPort(windowMgrPort);
- oldFont = qd.thePort->txFont;
- TextFont(systemFont);
-
- aTEHandle = TENew(&textRect,&textRect);
- TESetText(&errorString[1],errorString[0],aTEHandle);
- textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
- TEDispose(aTEHandle);
-
- additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
- - errorTextItem->boundsRect.top);
-
- if (additionalSpaceNeeded > 0)
- {
- (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
- errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
- OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
- }
-
- TextFont(oldFont);
- SetPort(oldPort);
-
- InitCursor();
- ParamText(errorString,nullStr,nullStr,nullStr);
-
- (void) StandardAlert(kErrorAlertID);
-
- ReleaseResource((Handle) errorDialogTemplate);
- ReleaseResource((Handle) errorDialogItems);
- }
-
-
- ///////////////////////////////////////////////////////////
- //
- // FatalErrorAlert
- //
- // A companion to ErrorAlert which also kills the process.
- //
-
- void
- FatalErrorAlert(short stringList,short whichString)
- {
- ErrorAlert(stringList,whichString);
- ExitToShell();
- }
-
-
- ///////////////////////////////////////////////////////////
- //
- // StandardDialogFilter and StandardDialogFilterYD
- //
- // These function takes care of routing events not meant
- // for the dialog window to other parts of the application.
- //
- // Use them as an alternative to passing a NIL ModalFilterProc
- // to ModalDialog() and CustomGet(Put)File. Unlike the default
- // filter, these routines properly processes update events
- // to keep background processes running.
- //
- // The Thread Manager, if present, is also called to yield
- // control to other cooperative threads within the process.
- //
- // Because of pascal calling conventions we need two separate
- // routines, but this is minimized by sharing implementation
- // in FilterProcCommon.
- //
-
- ModalFilterUPP StandardDialogFilter
- = NewModalFilterProc(StandardDialogFilterProc);
-
- ModalFilterYDUPP StandardDialogFilterYD
- = NewModalFilterYDProc(StandardDialogFilterYDProc);
-
- ModalFilterUPP StandardCloseDialogFilter
- = NewModalFilterProc(StandardCloseDialogFilterProc);
-
-
- pascal Boolean
- StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
- {
- // Call through common code to check for events we’d like to handle.
- // If that is unsuccessful, call through the System 7 StdFilterProc
- // to handle CR, “CMD-.” & ESC in an international-friendly manner.
-
- if (FilterProcCommon(theDialog, anEvent, itemHit))
- return true;
- else
- return (StdFilterProc(theDialog, anEvent, itemHit));
- }
-
-
- pascal Boolean
- StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
- {
- // We don’t call through to StdFilterProc since the
- // Standard File Package already does everything we need.
-
- return FilterProcCommon(theDialog, anEvent, itemHit);
- }
-
- void
- PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
- {
- Handle itemHandle;
- Rect itemBox;
- long finalTicks;
- short itemType;
-
- GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
-
- HiliteControl((ControlHandle) itemHandle,inButton);
- Delay(8,&finalTicks);
- HiliteControl((ControlHandle) itemHandle,0);
- }
-
-
- pascal Boolean
- StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
- {
- if ((anEvent->what == keyDown))
- {
- char c = (char) anEvent->message & charCodeMask;
-
- if ((c == 'd') || (c == 'D')) // NOT INTERNATIONAL FRIENDLY!!!
- {
- *itemHit = kDontSaveDocument;
- PseudoClickInDialogItem(theDialog,kDontSaveDocument);
- return true;
- }
- }
-
- // Return through the common code above so that default item processing can happen
- return StandardDialogFilterProc(theDialog, anEvent, itemHit);
- }
-
-
- Boolean
- FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
- {
- switch (anEvent->what)
- {
- case updateEvt:
- case activateEvt:
- // Update or activate for the dialog window?
- if (theDialog == (DialogPtr) anEvent->message)
- break;
-
- // no, fall through to HandleEvent
-
- case diskEvt:
- HandleEvent(anEvent);
- return(false);
-
- default:
- break;
- }
-
- if (gHasThreadManager) // If we have threads, let them run!
- YieldToAnyThread();
-
- return false; // We didn’t handle the event
- }
-
-
- //////////////////////////////////////////////////////////////////
- //
- // StandardCloseDocument
- //
- // Provides the standard human interface for closing a document
- //
- // NOTE: When we make TDocument class, this will become a method
- // and probably won’t need any parameters.
- //
- // NOTE: StandardCloseResult matches the dialog items for
-
- StandardCloseResult
- StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
- Boolean hasNewEditions, Boolean quitting)
- {
- short whichAlert;
- short whichString;
- StringPtr nullStr = (StringPtr) "\p";
- Str255 reasonForClosingStr;
-
- if (hasNewEditions)
- whichAlert = kStandardCloseWithNewPubsAlertID;
- else
- whichAlert = kStandardCloseAlertID;
-
- if (quitting)
- whichString = kQuittingStr;
- else
- whichString = kClosingStr;
-
- GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
- ParamText(documentType,documentName,reasonForClosingStr,nullStr);
-
- return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
- }
-